﻿@inherits FluxorComponent
@using Fluxor.Blazor.Web.Components;
@using SimpleIdServer.Configuration;
@using SimpleIdServer.Configuration.Models
@using SimpleIdServer.IdServer.Api.ConfDefs
@using SimpleIdServer.IdServer.Website.Resources;
@using SimpleIdServer.IdServer.Website.Stores.AuthMethodsStore;
@using SimpleIdServer.IdServer.Website.Stores.ConfigurationDefinitionStore;
@using SimpleIdServer.IdServer.Website.Stores.IdProviderStore;
@inject IState<ConfigurationDefinitionsState> configurationDefsState;
@inject IState<AuthMethodsState> authMethodsState;

@if(Properties != null)
{
    <RadzenTemplateForm @ref="settingForm" TItem="List<EditableProperty>" Data=@Properties>
        <RadzenStack>
            @if(!Properties.Any())
            {
                <RadzenAlert AllowClose="false" AlertStyle="AlertStyle.Danger" ShowIcon="true" Variant="Variant.Flat" Shade="Shade.Lighter">@Global.NoProperties</RadzenAlert>
            }
            else
            {
                @foreach (var property in Properties.OrderBy(p => p.Order))
                {
                    var componentName = Guid.NewGuid().ToString();
                    @if (property.Type != ConfigurationDefinitionRecordTypes.CHECKBOX && property.Type != ConfigurationDefinitionRecordTypes.OTPVALUE && property.Type != ConfigurationDefinitionRecordTypes.NOTIFICATIONMODE)
                    {
                        <RadzenFormField Text="@property.DisplayName" Variant=Variant.Outlined>
                            <ChildContent>
                                @switch (property.Type)
                                {
                                    case ConfigurationDefinitionRecordTypes.INPUT:
                                        <RadzenTextBox Name="@componentName" @bind-Value="@property.Value"></RadzenTextBox>
                                        break;
                                    case ConfigurationDefinitionRecordTypes.PASSWORD:
                                        <RadzenPassword Name="@componentName" @bind-Value="@property.Value"></RadzenPassword>
                                        break;
                                    case ConfigurationDefinitionRecordTypes.NUMBER:
                                        <RadzenNumeric Name="@componentName" @bind-Value="@property.Value"></RadzenNumeric>
                                        break;
                                    case ConfigurationDefinitionRecordTypes.SELECT:
                                        <RadzenDropDown Name="@componentName" @bind-Value="@property.Value" Data="@property.PossibleValues" Change="@((o) => Select(property, o))" TextProperty="Name" ValueProperty="Value" />
                                        break;
                                }
                            </ChildContent>
                            <Helper>
                                <RadzenStack>
                                    <div>
                                        <RadzenText TextStyle="TextStyle.Caption">@property.Description</RadzenText>
                                    </div>
                                    @if (property.IsRequired)
                                    {
                                        <RadzenRequiredValidator Component="@componentName" Text="@Global.Required"></RadzenRequiredValidator>
                                    }
                                </RadzenStack>
                            </Helper>
                        </RadzenFormField>
                    }
                    else if (property.Type == ConfigurationDefinitionRecordTypes.OTPVALUE)
                    {
                        <RadzenRow Gap="1rem">
                            <RadzenColumn Size="10">
                                <RadzenFormField Class="w-100" Text="@property.DisplayName" Variant=Variant.Outlined>
                                    <ChildContent>
                                        <RadzenTextBox Name="@componentName" @bind-Value="@property.Value"></RadzenTextBox>
                                    </ChildContent>
                                    <Helper>
                                        <RadzenText TextStyle="TextStyle.Caption">@property.Description</RadzenText>
                                        @if (property.IsRequired)
                                        {
                                            <RadzenRequiredValidator Component="@componentName" Text="@Global.Required"></RadzenRequiredValidator>
                                        }
                                    </Helper>
                                </RadzenFormField>
                            </RadzenColumn>
                            <RadzenColumn><RadzenButton Click="@((args) => GenerateOTPValue(property))" ButtonStyle="ButtonStyle.Secondary" Text="Generate OTP Value"></RadzenButton></RadzenColumn>
                        </RadzenRow>
                    }
                    else if (property.Type == ConfigurationDefinitionRecordTypes.NOTIFICATIONMODE)
                    {
                        <RadzenFormField Text="@property.DisplayName" Variant=Variant.Outlined>
                            <ChildContent>
                                <RadzenDropDown @bind-Value="@property.Value"
                                                Name="@componentName"
                                                Data="@authMethodsState.Value.AuthenticationMethods.Where(m => m.Capabilities.HasFlag(AuthenticationMethodCapabilities.PUSHNOTIFICATION))"
                                                TextProperty="Name"
                                                ValueProperty="Id" />
                            </ChildContent>
                            <Helper>
                                <RadzenText TextStyle="TextStyle.Caption">@property.Description</RadzenText>
                                @if (property.IsRequired)
                                {
                                    <RadzenRequiredValidator Component="@componentName" Text="@Global.Required"></RadzenRequiredValidator>
                                }
                            </Helper>
                        </RadzenFormField>
                    }
                    else if (property.Type == ConfigurationDefinitionRecordTypes.CHECKBOX)
                    {
                        <div>
                            <div>
                                <RadzenCheckBox @bind-Value="@property.ValueBoolean" Change="@((bool b) => Select(property, b))" Name="Checkbox" />
                                <RadzenLabel Text="@property.DisplayName" Component="Checkbox" Style="margin-left: 8px; vertical-align: middle;" />
                            </div>
                            <p class="text-muted">@property.Description</p>
                        </div>
                    }
                }            
            }
        </RadzenStack>

        @if(IsEnabled)
        {
            <RadzenButton class="mt-1" Variant="Variant.Flat" ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Success" Text="@(IsUpdating ? (IsAddForm ? Global.Adding : Global.Updating) : (IsAddForm ? Global.Add : Global.Update))" Disabled=@IsUpdating Click="@(args => UpdateConfiguration())" />
        }
    </RadzenTemplateForm>
}
    
@code {
    [Parameter]
    public string Name { get; set; } = null;
    [Parameter]
    public Dictionary<string, string> Values { get; set; }
    [Parameter]
    public bool IsUpdating { get; set; }
    [Parameter]
    public bool IsAddForm { get; set; } = false;
    [Parameter]
    public bool IsEnabled { get; set; } = true;
    [Parameter]
    public EventCallback<Dictionary<string, string>> PropertiesSaved { get; set; }
    List<EditableProperty> AllProperties { get; set; }
    List<EditableProperty> Properties { get; set; }
    RadzenTemplateForm<List<EditableProperty>> settingForm;

    record EditableProperty
    {
        public string Name { get; set; } = null!;
        public ConfigurationDefinitionRecordTypes Type { get; set; } = ConfigurationDefinitionRecordTypes.INPUT;
        public string DisplayName { get; set; }
        public string Description { get; set; }
        public string Value { get; set; }
        public bool ValueBoolean { get; set; }
        public int Order { get; set; }
        public string DisplayCondition { get; set; }
        public bool IsRequired { get; set; }
        public string GetValue()
        {
            if(Type == ConfigurationDefinitionRecordTypes.CHECKBOX) return ValueBoolean.ToString();
            return Value;
        }
        public ICollection<ConfigurationDefRecordValueResult> PossibleValues { get; set; } = new List<ConfigurationDefRecordValueResult>();
    }

    protected override void OnParametersSet()
    {
        base.OnParametersSet();
        if (configurationDefsState.Value.IsLoading || AllProperties != null || !configurationDefsState.Value.ConfigurationDefs.Any(d => d.Id == Name)) return;
        var configuration = configurationDefsState.Value.ConfigurationDefs.Single(c => c.Id == Name);
        AllProperties = configuration.Properties.Select(p => 
        {
            var vb = false;
            var value = Values != null && Values.ContainsKey(p.Name) ? Values[p.Name] : string.Empty;
            if(p.Type == ConfigurationDefinitionRecordTypes.CHECKBOX && bool.TryParse(value, out bool b))
                vb = b;

            var record = new EditableProperty
            {
                Name = p.Name,
                Type = p.Type,
                Order = p.Order,
                DisplayName = p.DisplayName,
                Description = p.Description,
                DisplayCondition = p.DisplayCondition,
                Value = value,
                ValueBoolean = vb,
                PossibleValues = p.PossibleValues,
                IsRequired = p.IsRequired
            };
            return record;
        }).ToList();
        Refresh();
    }

    async void UpdateConfiguration()
    {
        var values = GetValues();
        var anyRequiredValues = Properties.Any(p => p.IsRequired && values.Any(kvp => kvp.Key == p.Name && string.IsNullOrWhiteSpace(kvp.Value)));
        if (anyRequiredValues) return;
        await PropertiesSaved.InvokeAsync(values);
    }

    private void Select(EditableProperty p, object o)
    {
        p.Value = o.ToString();
        Refresh();
    }

    private void Select(EditableProperty p, bool o)
    {
        p.Value = o.ToString();
        Refresh();
    }

    private void Refresh()
    {
        var values = GetValues();
        var configuration = configurationDefsState.Value.ConfigurationDefs.Single(c => c.Id == Name);
        Properties = AllProperties.Where(p => DisplayConditionEvaluator.IsLogicalOperationValid(values, p.DisplayCondition)).ToList();
    }

    private Dictionary<string, string> GetValues()
    {
        var dic = AllProperties.ToDictionary(p => p.Name, p => p.GetValue());
        return dic;
    }

    private void GenerateOTPValue(EditableProperty property)
    {
        var key = KeyGeneration.GenerateRandomKey(20);
        property.Value = key.ConvertFromBase32();
    }
}